/* syscall.c : syscalls
 */

#include <kernel.h>
#include <stdarg.h>


static Syscall_args sys_args; //Statically allocated pointer to arguments for a create syscall

/* 
*	Generic syscall mechanism, taking an integer representing the type (see kernel.h for 
*	symbolic definitions) and a variable number of arguments. Positions those arguments in
*	memory, places the call type and a pointer to the arguments in eax/ecx, then initiates 
*	a trap into the kernel
*/
extern int syscall(int call, ...){
	int ret;
	va_list args;
	va_start(args, call);
	switch(call){
		case(REQ_CREATE):{
			sys_args.arg0 = (void (*)(void))va_arg(args, int);;
			sys_args.arg1 = va_arg(args, int); 
			break;
		}
		case(REQ_PUTS):{
			sys_args.arg0 = va_arg(args, char*);
			break;
		}

		case(REQ_SLEEP):{
			sys_args.arg0 = va_arg(args, unsigned int);			
			break;
		}
		case(REQ_SEND):
			sys_args.arg0 = va_arg(args, int);
			sys_args.arg1 = va_arg(args, void*);
			sys_args.arg2 = va_arg(args, int);
			break;
		case(REQ_RECV):
			sys_args.arg0 = va_arg(args, unsigned int*);
			sys_args.arg1 = va_arg(args, void*);
			sys_args.arg2 = va_arg(args, int);
			break;
		case(REQ_GETPID):
		case(REQ_YIELD): 
		case(REQ_STOP):
			break;
	}
	va_end(args);
	int argsloc = &sys_args;
	__asm __volatile("movl %[call], %%eax\n\t"	
			"movl %[argsloc], %%ecx\n\t"
			"int $63\n\t"
			"movl %%eax, %[ret]"
			:[call] "=m" (call), [argsloc] "=m" (argsloc), [ret] "=m" (ret)
			:
			:"%eax"
			);
	return ret;
}
/* Wrapper around syscall(REQ_CREATE, fn, stack) */
extern int syscreate(void (*fn)(), int stack){
	return syscall(REQ_CREATE, fn, stack);
}
/* Wrapper around syscall(REQ_YIELD) */
extern int sysyield(void){
	return syscall(REQ_YIELD);
}
/* Wrapper around syscall(REQ_STOP) */
extern int sysstop(void){
	return syscall(REQ_STOP);
}
extern unsigned int sysgetpid(void){
	return syscall(REQ_GETPID);
}
extern void sysputs( char *str ){
	syscall(REQ_PUTS, str);
}


// Wrapper around syscall(REQ_SLEEP);
extern void syssleep(int ms){
	syscall(REQ_SLEEP, ms);
}

extern int syssend(int dest_pid, void* buf, int len){
	return syscall(REQ_SEND, dest_pid, buf, len);
}

extern int sysrecv(unsigned int* from_pid, void* buf, int len){
	return syscall(REQ_RECV, from_pid, buf, len);
}
